package com.church.elim.dao;

import java.util.List;
import java.util.Arrays;

import java.math.BigInteger;

import java.lang.IllegalArgumentException;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;


import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.church.elim.domain.Church;
import com.church.elim.domain.Education;
import com.church.elim.domain.MaritalStatus;
import com.church.elim.domain.Parishioner;

@Repository("parishionerDAO")
public class ParishionerDAOImpl implements ParishionerDAO{
	@PersistenceContext
	private EntityManager entityManager;


	public List<Parishioner> findAllParishioners() {
		return entityManager.createQuery("SELECT o FROM Parishioner o", Parishioner.class).getResultList();
	}
	
	public List<Parishioner> findFilteredParishioners(String condition) {
		return entityManager.createQuery(
			    "select p1 from Parishioner p1, Person p2 where p1.id=p2.idPerson"
			    		+ condition, Parishioner.class).getResultList();
	}

	@Override
	@Transactional
	public void persist(Parishioner parishioner) {
		if (!isUniqueCnp(parishioner.getPerson().getCnp(), ""))
			throw new IllegalArgumentException("The CNP value is not unique.");
		entityManager.persist(parishioner);
	}
	
	@Override
	@Transactional
	public void flush() {
		entityManager.flush();
	}

	public List<MaritalStatus> getMaritalStatusList(){
		return Arrays.asList(MaritalStatus.values());
	}

	@Override
	public List<Education> getEducationList() {
		return Arrays.asList(Education.values());
	}

	@Override
	public Parishioner findParishioner(Long id) {
		return entityManager.find(Parishioner.class, id);
	}

	@Override
	@Transactional
	public void remove(Parishioner parishioner) {
		entityManager.remove(parishioner.getPerson());
	}
	

	private boolean isUniqueCnp (String cnp, String id){
		String queryString = "select count(*) from person where CNP is not null and CNP != \"\" and CNP=" + cnp;
		if (id.compareTo("") != 0)
			queryString += " and id_person != " + id;
		
		Query query = entityManager.createNativeQuery(queryString);
		if ( !((BigInteger) query.getSingleResult()).equals(BigInteger.valueOf(0)) )
			return false;
		
		return true;
	}
	
	@Override
	@Transactional
	public void updateParishioner(Parishioner parishioner) {
		String cnp = parishioner.getPerson().getCnp(); 
		if(cnp==null||cnp.trim().equals("")){
			throw new IllegalArgumentException("The CNP value is not set. Please set the CNP and retry!");
		}
		if (!isUniqueCnp(parishioner.getPerson().getCnp(), 
							parishioner.getPerson().getIdPerson().toString()))
			throw new IllegalArgumentException("The CNP value is not unique.");
		entityManager.merge(parishioner);
	}

	@Override
	public List<Parishioner> findPaginated(Integer page, Integer size) {
		Query typedQuery = entityManager.createQuery("SELECT o FROM Parishioner o", Parishioner.class);
		
		typedQuery.setFirstResult((page-1)*size);
		List<Parishioner> resultList = typedQuery.getResultList();
		return resultList;
	}
	
	@SuppressWarnings("rawtypes")
	@Override
	public List findAllParishioners(String columns){
		Query queryParishioners = entityManager.createNativeQuery(
			    "Select "+columns+" from Parishioner p1 JOIN Person p2 on p1.id_parishioner=p2.id_person");
		return queryParishioners.getResultList(); 
	}

	@Override
	public void updateChurch(Parishioner parishioner) {
		Parishioner p= findParishioner(parishioner.getId());
		p.setChurch(parishioner.getChurch());
		System.out.println("Updating church " + parishioner.getChurch() + 
				" for parishioner " + parishioner.getId());
		updateParishioner(p);
	}
}
